package com.base.system.config.jwt;

import cn.hutool.core.util.StrUtil;
import com.base.system.base.http.origin.AccessAllowOrigin;
import com.base.system.config.SpringContextUtil;
import com.base.system.enums.HttpStatus;
import com.base.system.service.UserService;
import com.base.system.service.impl.UserServiceImpl;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 对每次请求进行token认证
 * 确保在一次请求中只通过一次filter，而需要重复的执行
 */
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private JwtTokenProvider jwtTokenProvider;

    private JwtParameters parameters;

    private UserService userService;

    public JwtAuthenticationFilter() {
        jwtTokenProvider = SpringContextUtil.getBean(JwtTokenProvider.class);
        parameters = SpringContextUtil.getBean(JwtParameters.class);
        userService = SpringContextUtil.getBean(UserServiceImpl.class);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        //从请求中获取token
        String token = getJwtFromRequest(httpServletRequest);
        if (StrUtil.isNotEmpty(token) && jwtTokenProvider.validateToken(token)) {
            //校验通过
            String username = getAcountFromJwt(token, parameters.getTokenSecret());
            UserDetails userDetails = userService.loadUserByUsername(username);
            Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, token, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } else {
            log.error(httpServletRequest.getParameter("username") + " :Token is null");
            AccessAllowOrigin accessAllowOrigin = new AccessAllowOrigin(httpServletRequest, httpServletResponse);
            accessAllowOrigin.allowOrigin();
            accessAllowOrigin.write(HttpStatus.token_expired, "凭证无效，请先登录!");
        }
        super.doFilter(httpServletRequest,httpServletResponse,filterChain);
    }

    /**
     * 从请求头中获取Jwt信息
     */
    private String getJwtFromRequest(HttpServletRequest request){
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer")) return token.replace("Bearer ", "");
        return null;
    }

    /**
     * 从token中解析出账户信息
     * @param token jwtToken
     * @param signKey jwt token secret
     * @return
     */
    private String getAcountFromJwt(String token,String signKey){
        return Jwts.parser().setSigningKey(signKey)
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }
}
